/* NoX (NoC Simulator)
 *
 * Dept. of Computer Science & Engineering, Pennsylvania State University.
 * All Rights Reserved.
 *  
 * 1. License     
 * NoX is distributed free of charge for academic, educational, noncommercial 
 * research purposes as long as this notice in its entirety is preserved in
 * every file included in this package.
 * All commercial use of this program requires separate licence. Contact the
 * author for details.
 * 
 * 2. All the publications that used the simulation results generated by the 
 * NoX should notify the author of the publication information and put 
 * following reference.
 *
 *  http://www.cse.psu.edu/~dpark/nox/
 * 
 * 3. Modification of the source code is permitted and encouraged as long as 
 * it follows the terms described in this copyright notice.
 *
 * 4. The author is not responsible for any problems caused by possible errors
 * of the NoX package. Therefore, users should verify the simulation result
 * before using it in their publication.
 *
 * Dept. of Computer Science & Engineering, Pennsylvania State University.
 * Contact: dpark@cse.psu.edu 
 * 
 * 6. If problems are found with the NoX package, please send an email to the
 * author for discussion and correction.

 */

/* Update History
 *
 * Jan. 31, 2006  Version 1.0 released by Dongkook Park 
 *
 */

/* MULTIMEDIA.C - Generate multimedia traffic */

#include <stdlib.h>
#include <math.h>
#include "main.h"
#include "router.h"
#include "multimedia.h"
#include "shared.h"


double gaussian(double mean, const double sd)
{
  double x, y, r2;

  do
    {
      /* choose x,y in uniform square (-1,-1) to (+1,+1) */

      x = -1 + 2 * (double)(rand())/(RAND_MAX);
      y = -1 + 2 * (double)(rand())/(RAND_MAX);

      /* see if it is in the unit circle */
      r2 = x * x + y * y;
    }
  while (r2 > 1.0 || r2 == 0);

  /* Box-Muller ransform */
  return mean + sd * y * sqrt (-2.0 * log (r2) / r2);
}

/* Generate MPEG Video traffic */
int mpeg_generate(int trace_num, int f_num)
{

   double frame_mean, frame_sd;
   float frame_length, frame_cycles;
   float cycle_time = ((arch == 2)? CYCLE_TIME2 : CYCLE_TIME3) * 1E-9;
   char gop[GOP_SIZE] = {'I', 'B', 'B', 'P', 'B', 'B', 'P', 'B', 'B', 
                         'P', 'B', 'B', 'P', 'B', 'B'};


   switch (trace_num) {
      case 1 : /* Ayersroc */
         switch (gop[f_num%GOP_SIZE]) {
	    case 'I' :
	       frame_mean = AYER_I_MEAN;
	       frame_sd   = AYER_I_SD;
	       break;
	    case 'P' :
	       frame_mean = AYER_P_MEAN;
	       frame_sd   = AYER_P_SD;
	       break;
	    case 'B' :
	       frame_mean = AYER_B_MEAN;
	       frame_sd   = AYER_B_SD;
	       break;
	 }
	 break;

      case 2 : /* Flower Garden */
	 switch (gop[f_num%GOP_SIZE]) {
	    case 'I' :
	       frame_mean = FLOWER_I_MEAN;
	       frame_sd   = FLOWER_I_SD;
	       break;
	    case 'P' :
	       frame_mean = FLOWER_P_MEAN;
	       frame_sd   = FLOWER_P_SD;
	       break;
	    case 'B' :
	       frame_mean = FLOWER_B_MEAN;
	       frame_sd   = FLOWER_B_SD;
	       break;
	 }
	 break;

      case 3 : /* Football */
	 switch (gop[f_num%GOP_SIZE]) {
	    case 'I' :
	       frame_mean = FOOT_I_MEAN;
	       frame_sd   = FOOT_I_SD;
	       break;
            case 'P' :
	       frame_mean = FOOT_P_MEAN;
	       frame_sd   = FOOT_P_SD;
	       break;
	    case 'B' :
	       frame_mean = FOOT_B_MEAN;
	       frame_sd   = FOOT_B_SD;
	       break;
	 }
	 break;

      case 4 : /* Hook */
         switch (gop[f_num%GOP_SIZE]) {
	    case 'I' :
	       frame_mean = HOOK_I_MEAN;
	       frame_sd   = HOOK_I_SD;
	       break;
	    case 'P' :
	       frame_mean = HOOK_P_MEAN;
	       frame_sd   = HOOK_P_SD;
	       break;
	    case 'B' :
	       frame_mean = HOOK_B_MEAN;
	       frame_sd   = HOOK_B_SD;
	       break;
	 }
	 break;

      case 5 : /* Martin */
         switch (gop[f_num%GOP_SIZE]) {
	    case 'I' :
	       frame_mean = MARTIN_I_MEAN;
	       frame_sd   = MARTIN_I_SD;
	       break;
	    case 'P' :
	       frame_mean = MARTIN_P_MEAN;
	       frame_sd   = MARTIN_P_SD;
	       break;
	    case 'B' :
	       frame_mean = MARTIN_B_MEAN;
	       frame_sd   = MARTIN_B_SD;
	       break;
	 }
	 break;

      case 6 : /* Mobile Calendar */
         switch (gop[f_num%GOP_SIZE]) {
	    case 'I' :
	       frame_mean = MOBILE_I_MEAN;
	       frame_sd   = MOBILE_I_SD;
	       break;
	    case 'P' :
	       frame_mean = MOBILE_P_MEAN;
	       frame_sd   = MOBILE_P_SD;
	       break;
	    case 'B' :
	       frame_mean = MOBILE_B_MEAN;
	       frame_sd   = MOBILE_B_SD;
	       break;
	 }
	 break;

      case 7 : /* Table Tennis */
         switch (gop[f_num%GOP_SIZE]) {
	    case 'I' :
	       frame_mean = TENNIS_I_MEAN;
	       frame_sd   = TENNIS_I_SD;
	       break;
	    case 'P' :
	       frame_mean = TENNIS_P_MEAN;
	       frame_sd   = TENNIS_P_SD;
	       break;
	    case 'B' :
	       frame_mean = TENNIS_B_MEAN;
	       frame_sd   = TENNIS_B_SD;
	       break;
	 }
	 break;
   }
   
   frame_length = gaussian(frame_mean, frame_sd);
   //frame_cycles = (1.0/cycle_time)/60.0;
   frame_cycles = (1.0/cycle_time)/60000.0;

   // Determine intergeneration time of messages of this frame 
   // Message size is fixed with MSG_LEN                
   return (long) (frame_cycles / ((frame_length / (float)(MSG_LEN - 1)) + 1.0));

} // mpeg_generate() 

